<?php

// +----------------------------------------------------------------------
// | 处理支付相关的业务
// +----------------------------------------------------------------------
// | @author fancsen
// +----------------------------------------------------------------------

namespace app\api\service;

use app\common\lib\exception\ApiException;
use app\common\lib\enum\OrderStatusEnum;
use app\api\service\Order as OrderService;
use app\api\service\Token as TokenService;
use app\api\model\Order as OrderModel;
use think\Loader;
use think\Log;

Loader::import('WxPay.WxPay',EXTEND_PATH,'.Api.php');

class Pay
{
    private $orderID;
    private $orderNO;

    //构造方法
    public function __construct($orderID)
    {
        if(!$orderID){
            throw new \Exception("订单号不能为null");
        }
        $this->orderID = $orderID;
    }

    /**
     * 支付主体方法
     */
    public function pay()
    {
        //检测订单号
        $this->checkOrderValid();
        //重新检测商品库存
        $orderService = new OrderService();
        $pStatus = $orderService->checkOrderStock($this->orderID);
        if(!$pStatus['pass']){
            throw new ApiException("订单商品库存不足", 404,80002);
        }
        //调用微信预订单接口
        return $this->makePreOrder($pStatus['orderPrice']);
    }

    /**
     * 调用微信统一下单接口
     * @param float 订单总价
     * @return 返回调用结果
     */
    private function makePreOrder($totalPrice)
    {
        //获取用户openid
        $openid = TokenService::getCurrentTokenVar('openid');
        if(!$openid){
            throw new ApiException("Token已过期或无效Token", 403,10001); 
        }
        //实例化统一下单对象
        $wxOrderData = new \WxPayUnifiedOrder();
        $wxOrderData->SetOut_trade_no($this->orderNO);
        $wxOrderData->SetTrade_type('JSAPI');
        $wxOrderData->SetTotal_fee($totalPrice*100);
        $wxOrderData->SetBody('零食商贩');
        $wxOrderData->SetOpenid($openid);
        $wxOrderData->SetNotify_url(config('wx.notify_url'));
        return $this->getPaySignature($wxOrderData);
    }

    /**
     * 1调用微信预订单接口
     * 2储存返回结果中prepay_id
     * 3签名
     * @param object 预订单接口参数
     * @param 数据签名结果
     */
    private function getPaySignature($wxOrderData)
    {
        $wxOrder = \WxPayApi::unifiedOrder($wxOrderData);
        if($wxOrder['return_code'] != 'SUCCESS' ||
            $wxOrder['result_code'] !='SUCCESS'){
            Log::init([
                'type' => 'File',
                'path' => LOG_PATH,
                'level' => ['error']
            ]);
            Log::record($wxOrder,'error');
            Log::record('获取预支付订单失败','error');
            //return $wxOrder['return_msg'];
        }
       
        $this->recordPreOrder($wxOrder);
        $signature = $this->sign($wxOrder);
        return $signature;
    }

    /**
     * 签名
     */
    private function sign($wxOrder){
        $jsApiPayData = new \WxPayJsApiPay();
        $jsApiPayData->SetAppid(config('wx.app_id'));
        $jsApiPayData->SetTimeStamp((string)time());

        $rand = md5(time().mt_rand(0,1000));
        $jsApiPayData->SetNonceStr($rand);
        $jsApiPayData->SetPackage('prepay_id='.$wxOrder['prepay_id']);
        $jsApiPayData->SetSignType('md5');

        $sign = $jsApiPayData->MakeSign();
        $rawValues = $jsApiPayData->GetValues();
        $rawValues['paySign'] = $sign;

        unset($rawValues['appId']);

        return $rawValues;
    }

    /**
     * 将prepay_id更新导订单数据中
     * @param object 预订单接口返回参数
     */
    private function recordPreOrder($wxOrder)
    {
        OrderModel::where('id','=',$this->orderID)
            ->update(['prepay_id'=>$wxOrder['prepay_id']]);
    }

    /**
     * 执行支付前订单检测：
     * 1，检测订单号合法性:是否存在，是否和用户匹配
     * 2，检测订单是否已被支付
     * @return bool 
     */
    private function checkOrderValid()
    {
        $order = OrderModel::where('id','=',$this->orderID)->find();
        //是否存在
        if(!$order){
            throw new ApiException("订单不存在，请查id", 404,80003);    
        }
        //是否与用户匹配
        if(!TokenService::isValidOperate($order->user_id)){
            throw new ApiException("订单与用户不匹配", 400,80004);  
        }
        //订单是否已被支付过
        if($order->status != OrderStatusEnum::UNPAID){
            throw new ApiException("订单已被支付", 400,80005);  
        }
        $this->orderNO = $order->order_no;
        return true;
    }


}